import { _decorator, clamp, clamp01, Component, EventTouch, instantiate, Node, Prefab, Size, size, UITransform, v2, v3, Vec3, Widget } from 'cc';
const { ccclass, property } = _decorator;

const tmpP2_1 = v2();
const tmpP2_2 = v2();

// 列表数据必须实现的接口
export interface ICustomScollViewData {
    // 数据排列顺序ID
    idx: number;
    node: Node;
    init(...d): void;
    reset(...d): void;
    update(...d): void;
}
@ccclass('CustomVerticalScrollView')
/** 垂直 高性能滚动列表
 *  根据数据列表高度自动显示隐藏节点-节点复用
 * 
*/
export class CustomVerticalScrollView extends Component {

    itemPrefab: Prefab = null;

    // 数据
    itemDataArr: ICustomScollViewData[] = [];
    itemSize = size();
    // 布局参数
    @property
    spaceTop = 10;
    @property
    spaceBtm = 10;
    @property
    spaceY = 10;
    // 初始化数据
    initData(data: ICustomScollViewData[], itemPrefab: Prefab) {
        this.clear();
        this.itemDataArr = data;
        this.itemSize.set(itemPrefab.data.getComponent(UITransform).contentSize);
        this.itemPrefab = itemPrefab;
        this.initItems();
    }
    // 替换数据
    resetData(data: ICustomScollViewData[]) {
        this.clear();
        this.itemDataArr = data;
        this.initItems();
    }

    clear() {
        this.itemDataArr = null;
        this.clearItems();
    }

    onLoad(): void {
        this.initTouch();
    }
    onEnable() {
        this.enableTouch();
        this.enableItems();
    }
    update(dt: number) {
        this.updateItems(dt);
    }

    //#region --列表
    itemList: { data: ICustomScollViewData, initPos: Vec3, curPos: Vec3, tarPos: Vec3, isShow: boolean }[] = [];
    // 整体当前偏移
    allCurOffsetY = 0;
    // 整体目标偏移
    allTarOffsetY = 0;
    // 偏移范围
    offsetRange = { min: 0, max: 0 };
    //
    itemPool: Node[] = [];
    // 当前列表窗口大小
    curContentSize = size();

    private initItems() {
        // 创建items
        let offsetY = -(this.spaceTop + this.itemSize.height * 0.5);
        let pos = v3(0, 0);
        for (let i = 0; i < this.itemDataArr.length; i++) {
            const d = this.itemDataArr[i];
            pos.y = offsetY - (this.itemSize.height + this.spaceY) * i;
            this.itemList.push({ data: d, initPos: v3(pos), curPos: v3(pos), tarPos: v3(pos), isShow: false });
        }

        this.resetScorllRange();
        //
        // console.log('# offsetRange', this.itemDataArr.length, this.offsetRange);
    }

    private clearItems() {
        for (let i = 0; i < this.itemList.length; i++) {
            const item = this.itemList[i];
            item.data.reset();
            this.putItemNode(item.data.node);
            item.data.node = null;
        }
        this.itemList.length = 0;
    }

    @property
    useEnableAnim = true;
    private enableItems() {
        this.resetScorllRange();
        //
        this.allTarOffsetY = 0;
        // 当前值 初始设置偏移 -> 触发动画
        if (this.useEnableAnim) {
            this.allCurOffsetY = -this.itemSize.height * 1.5;
        } else {
            this.allCurOffsetY = 0;
        }
    }
    /** 重新计算滑动范围 */
    private resetScorllRange() {
        const wg = this.node.getComponent(Widget);
        wg && wg.updateAlignment();
        this.curContentSize.set(this.node.getComponent(UITransform).contentSize);
        // 滑动范围
        this.offsetRange.max = Math.max((this.itemDataArr.length * (this.itemSize.height + this.spaceY) + this.spaceTop + this.spaceBtm) - this.curContentSize.height, 0);
        this.offsetRange.min = 0;
    }
    /** 将指定索引滚动到屏幕中间 */
    scorllToIdx(idx: number) {
        if (!this.itemList[idx]) return;
        this.allTarOffsetY = -this.itemList[idx].initPos.y - this.curContentSize.height * 0.5;
        this.allTarOffsetY = clamp(this.allTarOffsetY, this.offsetRange.min, this.offsetRange.max);
    }

    private updateItems(dt) {
        // 整体偏移插值计算
        this.allCurOffsetY += (this.allTarOffsetY - this.allCurOffsetY) * 0.2;

        const maxY = this.itemSize.height + this.spaceY;
        const minY = -(this.curContentSize.height + this.itemSize.height + this.spaceY);

        for (let i = 0; i < this.itemList.length; i++) {
            const item = this.itemList[i];
            // 计算目标位置
            item.tarPos.y = item.initPos.y + this.allCurOffsetY;
            // 单个插值计算
            item.curPos.y += (item.tarPos.y - item.curPos.y) * 0.5;

            // 根据当前窗口高度判断是否显示
            item.isShow = item.curPos.y >= minY && item.curPos.y <= maxY;
            // 显示
            if (item.isShow) {
                if (!item.data.node) {
                    const node = this.getItemNode();
                    item.data.node = node;
                    item.data.node.active = true;
                    item.data.init();
                }
                item.data.node.setPosition(item.curPos);
                item.data.update(dt);
            }
            // 隐藏
            if (!item.isShow && item.data.node) {
                item.data.node.active = false;
                item.data.reset();
                this.putItemNode(item.data.node);
                item.data.node = null;
            }
        }
    }
    // 对象池
    private getItemNode(): Node {
        let item: Node = null;
        if (this.itemPool.length > 0) {
            item = this.itemPool.pop();
        } else {
            item = instantiate(this.itemPrefab);
        }
        item.parent = this.node;
        return item;
    }
    private putItemNode(item: Node) {
        if (!item) return;
        if (this.itemPool.indexOf(item) == -1) {
            this.itemPool.push(item);
            item.removeFromParent();
        }
    }

    //#endregion


    //#region --触摸

    isTouching = false;
    // 触摸开始时间
    _touchStartTime = 0;
    // 惯性速度 
    _inertanceSpeed = 0;

    private initTouch() {
        this.node.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
        this.node.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
        this.node.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
        this.node.on(Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
    }

    private enableTouch() {
        this.isTouching = false;
    }

    _preOffsetY = 0;
    private onTouchStart(event: EventTouch) {
        this._preOffsetY = this.allCurOffsetY;
        this.isTouching = true;
        // 惯性速度
        this._inertanceSpeed = 0;
        this._touchStartTime = Date.now();
        // 停止滑动
        this.allTarOffsetY = this.allCurOffsetY;
    }

    private onTouchMove(event: EventTouch) {
        event.getUIStartLocation(tmpP2_1);
        event.getUILocation(tmpP2_2);
        const subY = tmpP2_2.y - tmpP2_1.y;

        this.allTarOffsetY = this._preOffsetY + subY;
        // 50 表示 滑动时 可超出的距离
        this.allTarOffsetY = clamp(this.allTarOffsetY, this.offsetRange.min - 50, this.offsetRange.max + 50);

        // 惯性速度
        this._inertanceSpeed = subY * 60;
    }

    private onTouchEnd(event: EventTouch) {
        this.isTouching = false;

        // 计算惯性距离
        const subTime = (Date.now() - this._touchStartTime) / 1000;
        this._inertanceSpeed = (1 - clamp01(subTime / 0.3)) * this._inertanceSpeed * 0.1;
        this.allTarOffsetY = clamp(this.allTarOffsetY + this._inertanceSpeed, this.offsetRange.min, this.offsetRange.max);
    }

    //#endregion
}
